using FluffyUnderware.DevTools;
using FluffyUnderware.DevTools.Extensions;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace FluffyUnderware.Curvy.Controllers
{
	[RequireComponent(typeof(Text))]
	[AddComponentMenu("Curvy/Controller/UI Text Spline Controller")]
	[HelpURL("https://curvyeditor.com/doclink/uitextsplinecontroller")]
	public class UITextSplineController : SplineController, IMeshModifier
	{
		protected class GlyphQuad
		{
			public UIVertex[] V = new UIVertex[4];

			public Rect Rect;

			public Vector3 Center => Rect.center;

			public void Load(List<UIVertex> verts, int index)
			{
				V[0] = verts[index];
				V[1] = verts[index + 1];
				V[2] = verts[index + 2];
				V[3] = verts[index + 3];
				calcRect();
			}

			public void LoadTris(List<UIVertex> verts, int index)
			{
				V[0] = verts[index];
				V[1] = verts[index + 1];
				V[2] = verts[index + 2];
				V[3] = verts[index + 4];
				calcRect();
			}

			public void calcRect()
			{
				Rect = new Rect(V[0].position.x, V[2].position.y, V[2].position.x - V[0].position.x, V[0].position.y - V[2].position.y);
			}

			public void Save(List<UIVertex> verts, int index)
			{
				verts[index] = V[0];
				verts[index + 1] = V[1];
				verts[index + 2] = V[2];
				verts[index + 3] = V[3];
			}

			public void Save(VertexHelper vh)
			{
				vh.AddUIVertexQuad(V);
			}

			public void Transpose(Vector3 v)
			{
				for (int i = 0; i < 4; i++)
				{
					V[i].position += v;
				}
			}

			public void Rotate(Quaternion rotation)
			{
				for (int i = 0; i < 4; i++)
				{
					V[i].position = V[i].position.RotateAround(Center, rotation);
				}
			}
		}

		protected class GlyphPlain
		{
			public Vector3[] V = new Vector3[4];

			public Rect Rect;

			public Vector3 Center => Rect.center;

			public void Load(ref Vector3[] verts, int index)
			{
				V[0] = verts[index];
				V[1] = verts[index + 1];
				V[2] = verts[index + 2];
				V[3] = verts[index + 3];
				calcRect();
			}

			public void calcRect()
			{
				Rect = new Rect(V[0].x, V[2].y, V[2].x - V[0].x, V[0].y - V[2].y);
			}

			public void Save(ref Vector3[] verts, int index)
			{
				verts[index] = V[0];
				verts[index + 1] = V[1];
				verts[index + 2] = V[2];
				verts[index + 3] = V[3];
			}

			public void Transpose(Vector3 v)
			{
				for (int i = 0; i < 4; i++)
				{
					V[i] += v;
				}
			}

			public void Rotate(Quaternion rotation)
			{
				for (int i = 0; i < 4; i++)
				{
					V[i] = V[i].RotateAround(Center, rotation);
				}
			}
		}

		[Section("Orientation", true, false, 100)]
		[Tooltip("If true, the text characters will keep the same orientation regardless of the spline they follow")]
		[SerializeField]
		private bool staticOrientation;

		private Graphic m_Graphic;

		private RectTransform mRect;

		private Text mText;

		public bool StaticOrientation
		{
			get
			{
				return staticOrientation;
			}
			set
			{
				staticOrientation = value;
			}
		}

		protected override bool ShowOrientationSection => false;

		protected override bool ShowOffsetSection => false;

		protected Text Text
		{
			get
			{
				if (mText == null)
				{
					mText = GetComponent<Text>();
				}
				return mText;
			}
		}

		protected RectTransform Rect
		{
			get
			{
				if (mRect == null)
				{
					mRect = GetComponent<RectTransform>();
				}
				return mRect;
			}
		}

		protected Graphic graphic
		{
			get
			{
				if (m_Graphic == null)
				{
					m_Graphic = GetComponent<Graphic>();
				}
				return m_Graphic;
			}
		}

		public override CurvySpline Spline
		{
			get
			{
				return m_Spline;
			}
			set
			{
				if (m_Spline != value)
				{
					if (base.isInitialized)
					{
						UnbindSplineRelatedEvents();
					}
					m_Spline = value;
					if (base.isInitialized)
					{
						BindSplineRelatedEvents();
					}
				}
			}
		}

		protected override void InitializedApplyDeltaTime(float deltaTime)
		{
			base.InitializedApplyDeltaTime(deltaTime);
			graphic.SetVerticesDirty();
		}

		public void ModifyMesh(Mesh verts)
		{
			if (base.enabled && base.gameObject.activeInHierarchy && base.isInitialized)
			{
				Vector3[] verts2 = verts.vertices;
				GlyphPlain glyphPlain = new GlyphPlain();
				for (int i = 0; i < Text.text.Length; i++)
				{
					glyphPlain.Load(ref verts2, i * 4);
					float absolutePosition = base.AbsolutePosition;
					Vector2 center = glyphPlain.Rect.center;
					float position = absolutePosition + center.x;
					float tf = AbsoluteToRelative(CurvyController.GetClampedPosition(position, CurvyPositionMode.WorldUnits, base.Clamping, Length));
					Vector3 interpolatedSourcePosition = GetInterpolatedSourcePosition(tf);
					Vector3 tangent = GetTangent(tf);
					Vector3 v = interpolatedSourcePosition - Rect.position - glyphPlain.Center;
					GlyphPlain glyphPlain2 = glyphPlain;
					Vector3 center2 = glyphPlain.Center;
					glyphPlain2.Transpose(new Vector3(0f, center2.y, 0f));
					glyphPlain.Rotate(Quaternion.AngleAxis(Mathf.Atan2(tangent.x, 0f - tangent.y) * 57.29578f - 90f, Vector3.forward));
					glyphPlain.Transpose(v);
					glyphPlain.Save(ref verts2, i * 4);
				}
				verts.vertices = verts2;
			}
		}

		public void ModifyMesh(VertexHelper vertexHelper)
		{
			if (!base.enabled || !base.gameObject.activeInHierarchy || !base.isInitialized)
			{
				return;
			}
			List<UIVertex> list = new List<UIVertex>();
			GlyphQuad glyphQuad = new GlyphQuad();
			vertexHelper.GetUIVertexStream(list);
			vertexHelper.Clear();
			for (int i = 0; i < Text.text.Length; i++)
			{
				glyphQuad.LoadTris(list, i * 6);
				float absolutePosition = base.AbsolutePosition;
				Vector2 center = glyphQuad.Rect.center;
				float position = absolutePosition + center.x;
				float tf = AbsoluteToRelative(CurvyController.GetClampedPosition(position, CurvyPositionMode.WorldUnits, base.Clamping, Length));
				Vector3 interpolatedSourcePosition = GetInterpolatedSourcePosition(tf);
				Vector3 tangent = GetTangent(tf);
				Vector3 v = interpolatedSourcePosition - Rect.position - glyphQuad.Center;
				GlyphQuad glyphQuad2 = glyphQuad;
				Vector3 center2 = glyphQuad.Center;
				glyphQuad2.Transpose(new Vector3(0f, center2.y, 0f));
				if (!StaticOrientation)
				{
					glyphQuad.Rotate(Quaternion.AngleAxis(Mathf.Atan2(tangent.x, 0f - tangent.y) * 57.29578f - 90f, Vector3.forward));
				}
				glyphQuad.Transpose(v);
				glyphQuad.Save(vertexHelper);
			}
		}

		protected override void OnEnable()
		{
			base.OnEnable();
			if (graphic != null)
			{
				graphic.SetVerticesDirty();
			}
		}

		protected override void OnDisable()
		{
			base.OnDisable();
			if (graphic != null)
			{
				graphic.SetVerticesDirty();
			}
		}

		protected override void BindEvents()
		{
			base.BindEvents();
			BindSplineRelatedEvents();
		}

		protected override void UnbindEvents()
		{
			base.UnbindEvents();
			UnbindSplineRelatedEvents();
		}

		private void BindSplineRelatedEvents()
		{
			if ((bool)Spline)
			{
				UnbindSplineRelatedEvents();
				Spline.OnRefresh.AddListener(OnSplineRefreshed);
			}
		}

		private void UnbindSplineRelatedEvents()
		{
			if ((bool)Spline)
			{
				Spline.OnRefresh.RemoveListener(OnSplineRefreshed);
			}
		}

		private void OnSplineRefreshed(CurvySplineEventArgs e)
		{
			CurvySpline curvySpline = e.Sender as CurvySpline;
			if (curvySpline != Spline)
			{
				curvySpline.OnRefresh.RemoveListener(OnSplineRefreshed);
			}
			else
			{
				graphic.SetVerticesDirty();
			}
		}
	}
}
